0081. 搜索旋转排序数组 II【中等】
1. 📝 题目描述
已知存在一个按非降序排列的整数数组 nums,数组中的值不必互不相同。
在传递给函数之前,nums 在预先未知的某个下标 k(0 <= k < nums.length)上进行了 旋转,使数组变为 [nums[k], nums[k+1], ..., nums[n-1], nums[0], nums[1], ..., nums[k-1]](下标 从 0 开始 计数)。例如, [0,1,2,4,4,4,5,6,6,7] 在下标 5 处经旋转后可能变为 [4,5,6,6,7,0,1,2,4,4]。
给你 旋转后 的数组 nums 和一个整数 target,请你编写一个函数来判断给定的目标值是否存在于数组中。如果 nums 中存在这个目标值 target,则返回 true,否则返回 false。
你必须尽可能减少整个操作步骤。
示例 1:
txt
输入:nums = [2,5,6,0,0,1,2], target = 0
输出:true1
2
2
示例 2:
txt
输入:nums = [2,5,6,0,0,1,2], target = 3
输出:false1
2
2
提示:
1 <= nums.length <= 5000-10^4 <= nums[i] <= 10^4- 题目数据保证
nums在预先未知的某个下标上进行了旋转 -10^4 <= target <= 10^4
进阶:
- 此题与 搜索旋转排序数组 相似,但本题中的
nums可能包含 重复 元素。这会影响到程序的时间复杂度吗?会有怎样的影响,为什么?
2. 🎯 s.1 - 二分查找
c
bool search(int* nums, int numsSize, int target) {
int left = 0, right = numsSize - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] == target)
return true;
// 无法判断有序半边时,收缩边界
if (nums[left] == nums[mid]) {
left++;
continue;
}
if (nums[left] < nums[mid]) { // 左半段有序
if (nums[left] <= target && target < nums[mid])
right = mid - 1;
else
left = mid + 1;
} else { // 右半段有序
if (nums[mid] < target && target <= nums[right])
left = mid + 1;
else
right = mid - 1;
}
}
return false;
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
js
/**
* @param {number[]} nums
* @param {number} target
* @return {boolean}
*/
var search = function (nums, target) {
let left = 0,
right = nums.length - 1
while (left <= right) {
const mid = (left + right) >> 1
if (nums[mid] === target) return true
// 无法判断有序半边时,收缩边界
if (nums[left] === nums[mid]) {
left++
continue
}
if (nums[left] < nums[mid]) {
// 左半段有序
if (nums[left] <= target && target < nums[mid]) right = mid - 1
else left = mid + 1
} else {
// 右半段有序
if (nums[mid] < target && target <= nums[right]) left = mid + 1
else right = mid - 1
}
}
return false
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
py
class Solution:
def search(self, nums: List[int], target: int) -> bool:
left, right = 0, len(nums) - 1
while left <= right:
mid = (left + right) // 2
if nums[mid] == target:
return True
# 无法判断有序半边时,收缩边界
if nums[left] == nums[mid]:
left += 1
continue
if nums[left] < nums[mid]: # 左半段有序
if nums[left] <= target < nums[mid]:
right = mid - 1
else:
left = mid + 1
else: # 右半段有序
if nums[mid] < target <= nums[right]:
left = mid + 1
else:
right = mid - 1
return False1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
- 时间复杂度:
,最坏情况全部重复时退化为 - 空间复杂度:
,只使用常数额外空间
算法思路:
- 与 0033 类似,通过二分查找判断 target 在有序的哪一半
- 区别在于存在重复元素:当
nums[left] == nums[mid]时无法判断有序半边,此时left++跳过重复值 - 否则根据左半段或右半段有序,判断 target 是否落在有序区间内,收缩边界